package lib

import (
	"fmt"
	"math"

	"GameServer/Common/data"
	"GameServer/Common/utils"
	"GameServer/Game/errors"
	"GameServer/Game/m"

	"github.com/globalsign/mgo/bson"
)

var (
	keyGoods         m.Goods = m.Goods{Tid: 150401, Num: 1} // 钥匙
	silverBoxGoods   m.Goods = m.Goods{Tid: 150201, Num: 1} // 铜宝箱
	copperBoxGoods   m.Goods = m.Goods{Tid: 150202, Num: 1} // 银宝箱
	nextBlockGoods   m.Goods = m.Goods{Tid: 150405, Num: 1} // 传送门
	goldGoods        m.Goods = m.Goods{Tid: 220001}         // 金币
	diamonGoods      m.Goods = m.Goods{Tid: 220002}         // 砖石
	energyGoods      m.Goods = m.Goods{Tid: 220004}         // 体力
	starGoods        m.Goods = m.Goods{Tid: 220005}         // 星星
	shieldGoods      m.Goods = m.Goods{Tid: 220007}         // 盾牌
	lowBrickColor    uint64  = 1
	openDoorGoods    m.Goods = m.Goods{Tid: 150404, Num: 1} // 开启门物品
	closeDoorGoods   m.Goods = m.Goods{Tid: 150403, Num: 1} // 关闭门的物品
	inDoorGoods      m.Goods = m.Goods{Tid: 150402, Num: 1} // 入口
	roadSign         m.Goods = m.Goods{Tid: 150407, Num: 1} // 路标
	unionScoreGoods  m.Goods = m.Goods{Tid: 220006, Num: 1} // 公会积分
	tvGoods          m.Goods = m.Goods{Tid: 150410, Num: 1} // 电视机
	bombGoods        m.Goods = m.Goods{Tid: 150501, Num: 1} // 炸弹
	crystalballGoods m.Goods = m.Goods{Tid: 150411, Num: 1} // 水晶球

	magicBookRedGoods    m.Goods = m.Goods{Tid: 150512, Num: 1} // 魔法书-红
	magicBookBlueGoods   m.Goods = m.Goods{Tid: 150513, Num: 1} // 魔法书-蓝
	magicBookPurpleGoods m.Goods = m.Goods{Tid: 150514, Num: 1} // 魔法书-紫

	driftingBottleGoods m.Goods = m.Goods{Tid: 150413, Num: 1} // 漂流瓶

	christmasBallGoods     m.Goods = m.Goods{Tid: 150521, Num: 1} // 圣诞装饰球
	christmasCandyGoods    m.Goods = m.Goods{Tid: 150522, Num: 1} // 圣诞拐棍糖
	christmasStockingGoods m.Goods = m.Goods{Tid: 150523, Num: 1} // 圣诞袜
)

func generateLayerFirst(layerT data.Layer, layer *m.Layer) (err error) {
	lists, ok := data.GetAllDatas("FirstLayers")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "未找到FirstLayers")
		return
	}

	layer.GridList = make(map[int64]*m.GridInfo, 0)

	for _, item := range lists {
		grid := item.(data.FirstLayer)
		g := &m.GridInfo{
			Id:     int64(grid.Gid),
			Tid:    int64(grid.Gtid),
			Status: 1,
		}
		if grid.Gtid == 0 {
			g.Status = 0
		}
		if grid.GoodsId != 0 {
			g.Goods = &m.Goods{
				Tid: int64(grid.GoodsId),
				Num: 1,
			}
		}
		layer.GridList[int64(grid.Gid)] = g
	}
	return
}

// 生成第二层配置
func generateLayerSecond(layerT data.Layer, layer *m.Layer) (err error) {
	lists, ok := data.GetAllDatas("SecondLayers")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "未找到SecondLayers")
		return
	}

	layer.GridList = make(map[int64]*m.GridInfo, 0)

	for _, item := range lists {
		grid := item.(data.FirstLayer)
		g := &m.GridInfo{
			Id:     int64(grid.Gid),
			Tid:    int64(grid.Gtid),
			Status: 1,
		}
		if grid.Gtid == 0 {
			g.Status = 0
		}
		if grid.GoodsId != 0 {
			g.Goods = &m.Goods{
				Tid: int64(grid.GoodsId),
				Num: 1,
			}
		}
		layer.GridList[int64(grid.Gid)] = g
	}
	return
}

//生成 层级
func generateLayer(layerT data.Layer, layer *m.Layer, lockBlock *m.LockBlock) (err error) {
	switch layerT.Layer_type {
	case 0:
		err = generateLayerNormal(layerT, layer, lockBlock)
	case 1:
		err = generateLayerBoss(layerT, layer, lockBlock)
	}
	return
}

//生成普通层级
func generateLayerNormal(layerT data.Layer, layer *m.Layer, lockBlock *m.LockBlock) (err error) {
	num := int(layerT.Column) * 7
	layer.GridList = make(map[int64]*m.GridInfo, 0)
	mGridT := make(map[int64]data.Brick, 0)
	// 按比列生成砖块
	lessNum := num
	var gidList []uint64
	var percent float64 = 100
	for _, item := range layerT.Grids {
		if utils.Int64(item.Weight) == 0 {
			// 权重为0， 不生成砖块
			continue
		}
		tnumf := float64(float64(utils.Int64(item.Weight)) / percent * float64(num))
		tnum := int(tnumf)
		gid := utils.Uint64(item.Value)

		for i := 0; i < tnum; i++ {
			gidList = append(gidList, gid)
		}
		lessNum -= tnum
	}

	for i := 0; i < lessNum; i++ {
		w := utils.RandomWeight(layerT.Grids)
		gid := utils.Uint64(w.Value)
		gidList = append(gidList, gid)
	}

	mIndex := make(map[int]int, 0)
	for i := 0; i < num; i++ {
		mIndex[i] = i
	}
	gridAutoId := 0
	for index := range mIndex {
		gid := gidList[index]
		grid, gridT, err := generateGrid(gid)
		if err != nil {
			return err
		}

		i := int64(gridAutoId)
		grid.Id = i
		layer.GridList[i] = grid
		mGridT[i] = gridT
		gridAutoId++
	}

	// 按比列生成砖块 end

	// 生成祭坛
	for _, altar := range layer.Altars {
		altarT := mAltarT[altar.Typ]
		for _, gid := range altar.GridIds {
			layer.GridList[gid].Goods = &m.Goods{Tid: altarT.goodsTid, Num: 1}
			delete(mGridT, gid)
		}
	}

	// 生成祭坛 end

	// 故事绘所在的id列表
	mStoryIds := make(map[int64]int64, 0)

	for _, id := range layer.StoryGridIds {
		mStoryIds[id] = id
	}

	var gridIds []int64
	for id, _ := range mGridT {
		// 必出物品不能出现在 故事绘里面
		if _, ok := mStoryIds[id]; ok {
			continue
		}
		gridIds = append(gridIds, id)
	}

	var openId int64 = -1
	// 生成必出物品
	for _, resItem := range layerT.Res {
		sum := int(utils.Int64(resItem.Value))

		for i := 0; i < sum; i++ {
			gid, newList := getRandomList(gridIds)
			layer.GridList[gid].Goods = &m.Goods{Tid: int64(resItem.Key), Num: 1}
			gridIds = newList
			delete(mGridT, gid)
			if inDoorGoods.Tid == int64(resItem.Key) {
				openId = gid
				layer.GridList[gid].Status = 0
			}
			if roadSign.Tid == int64(resItem.Key) {
				openId = gid
				layer.GridList[openId].Status = 0
			}
		}
	}

	layer.InGridId = openId

	// 生成星星
	var genStarNum int64 = 0
	for gid, _ := range mGridT {
		if genStarNum == layer.StarNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: starGoods.Tid, Num: 1}
		genStarNum += 1
		delete(mGridT, gid)
	}
	// 生成电视机
	var genTvNum int64 = 0
	for gid, _ := range mGridT {
		if genTvNum == layer.TvNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: tvGoods.Tid, Num: 1}
		genTvNum += 1
		delete(mGridT, gid)
	}

	// 生成炸弹
	var genBombNum int64 = 0
	for gid, _ := range mGridT {
		if genBombNum == layer.BombNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: bombGoods.Tid, Num: 1}
		genBombNum += 1
		delete(mGridT, gid)
	}

	// 生成水晶球
	var genCrystalballNum int64 = 0
	for gid, _ := range mGridT {
		if genCrystalballNum == layer.CrystalballNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: crystalballGoods.Tid, Num: 1}
		genCrystalballNum += 1
		delete(mGridT, gid)
	}

	// 生成魔法书-红
	var genMBRedNum int64 = 0
	for gid, _ := range mGridT {
		if genMBRedNum == layer.MagicBookRedNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: magicBookRedGoods.Tid, Num: 1}
		genMBRedNum += 1
		delete(mGridT, gid)
	}
	// 生成魔法书-蓝
	var genMBBlueNum int64 = 0
	for gid, _ := range mGridT {
		if genMBBlueNum == layer.MagicBookBlueNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: magicBookBlueGoods.Tid, Num: 1}
		genMBBlueNum += 1
		delete(mGridT, gid)
	}
	// 生成魔法书-紫
	var genMBPurpleNum int64 = 0
	for gid, _ := range mGridT {
		if genMBPurpleNum == layer.MagicBookPurpleNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: magicBookPurpleGoods.Tid, Num: 1}
		genMBPurpleNum += 1
		delete(mGridT, gid)
	}

	// 生成漂流瓶
	var genDriftingBottleNum int64 = 0
	for gid, _ := range mGridT {
		if genDriftingBottleNum == layer.DriftingBottleNum {
			break
		}
		layer.GridList[gid].Goods = &m.Goods{Tid: driftingBottleGoods.Tid, Num: 1}
		genDriftingBottleNum += 1
		delete(mGridT, gid)
	}

	// 生成怪物
	if monster, ok := lockBlock.Monsters[layer.Tid]; ok {
		for monsterId, monsterNum := range monster {
			monsterNumIndex := 0
			for gid, _ := range mGridT {
				if monsterNumIndex == int(monsterNum) {
					break
				}
				layer.GridList[gid].Goods = &m.Goods{Tid: monsterId, Num: 1}
				// 如果是新手地鼠人，格子打开。
				if monsterId == data.NewGuildMonsterTid {
					layer.GridList[gid].Status = 0
				}
				monsterNumIndex += 1
				delete(mGridT, gid)
			}
		}
	}

	filterGoods := make(map[int64]int64)
	// 没有活动开启，过滤道具
	if _, err := GetCurrentChristmasActivity(); err != nil {
		filterGoods[christmasBallGoods.Tid] = christmasBallGoods.Tid
		filterGoods[christmasCandyGoods.Tid] = christmasCandyGoods.Tid
		filterGoods[christmasStockingGoods.Tid] = christmasStockingGoods.Tid
	}
	// 没有活动开启，过滤道具
	lst := GetNoColloctPropActivityGoodTid()
	for _, item := range lst {
		filterGoods[item] = item
	}

	// 生成随机物品
	for gid, gridT := range mGridT {
		// 活动没有开启，需要把活动的道具过滤掉
		rewards := make([]data.WeightKV, 0)
		for _, item := range gridT.Rewards {
			if _, ok := filterGoods[int64(item.Key)]; ok {
				continue
			}
			rewards = append(rewards, item)
		}
		gridT.Rewards = rewards
		layer.GridList[gid].Goods = generateGridGoods(gridT)
	}
	return
}

//生成Boss层级
func generateLayerBoss(layerT data.Layer, layer *m.Layer, lockBlock *m.LockBlock) (err error) {
	num := int(layerT.Column) * 7
	layer.GridList = make(map[int64]*m.GridInfo, 0)

	var gid int64
	//var grid *m.GridInfo
	//grid = g
	for i := 0; i < num; i++ {
		gid := int64(i)
		g := &m.GridInfo{
			Tid:    0,
			Status: 0,
		}
		g.Id = gid
		layer.GridList[gid] = g
	}

	var openId int64 = -1
	// 生成必出物品
	for _, resItem := range layerT.Res {
		if nextBlockGoods.Tid == int64(resItem.Key) { //判断物品是传送门
			gid = int64(num - 1)
			layer.GridList[gid].Goods = &m.Goods{Tid: int64(resItem.Key), Num: 1}
		} else if inDoorGoods.Tid == int64(resItem.Key) { //判断物品是入口
			gid = 0
			openId = gid
			layer.GridList[gid].Goods = &m.Goods{Tid: int64(resItem.Key), Num: 1}
		} else {
			tpl, ok := data.Get("CardMonsters", uint64(resItem.Key))
			if ok && int64(tpl.(data.CardMonster).Type) != data.CardMonsterTypeEnum.Normal {
				gid = int64(num/2) - 1
				layer.GridList[gid].Goods = &m.Goods{Tid: int64(resItem.Key), Num: 1}
			}
		}
	}

	layer.InGridId = openId
	return
}

func getRandomList(list []int64) (r int64, newList []int64) {
	index := utils.RandomInt64(0, int64(len(list))-1)
	r = list[index]
	for _, v := range list {
		if v == r {
			continue
		}
		newList = append(newList, v)
	}
	return
}

func generateLayer2(layer *m.Layer, lockBlock *m.LockBlock) (err error) {
	layerT, ok := getLayerTByTid(uint64(layer.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "未找到该层级信息")
		return
	}
	return generateLayer(layerT, layer, lockBlock)

}

//  生成第一关
func GenerateLockBlockFirst(uid string) (r *m.LockBlock, err error) {
	lockBlockTpl, ok := data.Get("LevelDoors", uint64(1))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到关卡配置表,id:%d", 1))
		return
	}
	lockBlockT := lockBlockTpl.(data.LevelDoor)

	r = &m.LockBlock{
		Mid:         bson.NewObjectId().Hex(),
		Uid:         uid,
		Tid:         int64(1),
		Star:        0,
		StarNum:     utils.Int64(lockBlockT.Star.Value),
		Status:      0,
		GridOpenNum: 0,
		Layers:      make(map[int64]string, 0),
		Monsters:    make(map[int64]map[int64]int64, 0),
		Story:       &m.Story{},
	}

	var layersTList []data.Layer //关卡所有层级

	layerId := 1
	for {
		layerT, ok := getLayerT(uint64(1), uint64(layerId))
		if !ok {
			break
		}
		layersTList = append(layersTList, layerT)
		layerId++
	}

	var gridNumSum int64 = 0

	genStarNum := r.StarNum
	for _, layerT := range layersTList {
		gridNum := 7 * layerT.Column
		gridNumSum += int64(gridNum)
		layer := &m.Layer{Tid: int64(layerT.Id), Id: int64(layerT.LayerId), StarNum: genStarNum, Uid: uid, Mid: bson.NewObjectId().Hex()}
		if layerT.LayerId == 1 {
			layer.StarNum = 8
			genStarNum -= 8
			err := generateLayerFirst(layerT, layer)
			if err != nil {
				return nil, err
			}
		}
		if layerT.LayerId == 2 {
			layer.StarNum = 9
			genStarNum -= 9
			err := generateLayerSecond(layerT, layer)
			if err != nil {
				return nil, err
			}
		}
		r.Layers[int64(layerT.LayerId)] = layer.Mid
		// m.Cache.Put("layer", layer.Mid, layer)
		layer.Update(layer)
	}
	r.GridNum = gridNumSum - int64(len(r.Layers))
	return
}

//获取可用于生成物品的楼层数量
func GetLayerNumCanGenerateItem(layersTList []data.Layer) (length int) {
	length = 0
	for _, item := range layersTList {
		if item.Layer_type == 0 {
			length++
		}
	}
	return
}

// 生成关卡信息
func GenerateLockBlock(us *m.User, id uint64, oldLockBlock *m.LockBlock, robot bool) (r *m.LockBlock, err error) {
	uid := us.Uid.Hex()
	// 生成关卡祭坛
	altarMessageTpl, ok := data.Get("AltarMessages", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到祭坛配置表,id:%d", id))
		return
	}
	altarMessageT := altarMessageTpl.(data.AltarMessage)

	altarKindList, ok := data.GetAllDatas("AltarKinds")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到祭坛类别信息")
		return
	}

	checkInAltarTypes := func(id uint64, ids []uint64) bool {
		for _, item := range ids {
			if id == item {
				return true
			}
		}
		return false
	}

	var altarKindWeights []data.WeightV

	for _, item := range altarKindList {
		itemv := item.(data.AltarKind)
		if checkInAltarTypes(itemv.Type, altarMessageT.AltarTypes) && itemv.Status == 0 {
			altarKindWeights = append(altarKindWeights, data.WeightV{Weight: itemv.Weight, Value: itemv})
		}
	}

	var layersTList []data.Layer //关卡所有层级

	layerId := 1
	for {
		layerT, ok := getLayerT(uint64(id), uint64(layerId))
		if !ok {
			break
		}
		layersTList = append(layersTList, layerT)
		layerId++
	}
	var gridNumSum int64 = 0

	mGridNum := make(map[uint64][]int64, 0) //可以生成的祭坛随机数组
	for _, layerT := range layersTList {
		gridNum := 7 * layerT.Column
		gridNumSum += int64(gridNum)
		mGridNum[layerT.Id] = []int64{1, 0}
		// if gridNum < 50 {
		// 	mGridNum[layerT.Id] = []int64{1, 0}
		// } else {
		// 	mGridNum[layerT.Id] = []int64{2, 1, 0}
		// }
	}

	lockBlockTpl, ok := data.Get("LevelDoors", uint64(id))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到关卡配置表,id:%d", id))
		return
	}
	lockBlockT := lockBlockTpl.(data.LevelDoor)

	var (
		storyLayerTindex int64 = 0
		storyLayerTid    int64 = 0
		storyLayerId     int64 = 0
	)

	layerLen := GetLayerNumCanGenerateItem(layersTList)
	// 找到需要生成绘本的 层信息   旧关卡不存在  或者旧关卡的故事绘本 没有集齐
	if lockBlockT.Story > 0 && (oldLockBlock == nil || oldLockBlock.Status == 0) {
		storyLayerTindex = utils.RandomInt64(0, int64(layerLen-1))
		storyLayerTid = int64(layersTList[storyLayerTindex].Id)     // 索引id
		storyLayerId = int64(layersTList[storyLayerTindex].LayerId) // 第几层
	}

	mAltarNum := make(map[uint64]int64, 0) //具体生成祭坛随机数组

	// 先随机生成一波祭坛数据
	var altarSum int64 = 0
	for id, list := range mGridNum {
		if storyLayerTid == int64(id) { // 如果是 故事绘， 不生成祭坛
			continue
		}
		num := utils.RandomInt64(0, int64(len(list))-1)
		if num == 0 {
			continue
		}
		altarSum += num
		if altarSum > int64(altarMessageT.AltarNum) {
			break
		}
		mAltarNum[id] = num
	}

	for id, _ := range mAltarNum {
		delete(mGridNum, id)
	}
	// 补充生成祭坛  直接range map  补充数据
	lessAltarNum := int64(altarMessageT.AltarNum) - altarSum
	for id, list := range mGridNum {
		if lessAltarNum <= 0 {
			break
		}
		if storyLayerTid == int64(id) { // 如果是 故事绘， 不生成祭坛
			continue
		}

		num := len(list) - 1
		if lessAltarNum < int64(num) {
			num = 1
		}
		mAltarNum[id] = int64(num)
		lessAltarNum -= int64(num)
	}

	r = &m.LockBlock{
		Mid:                bson.NewObjectId().Hex(),
		Uid:                uid,
		Tid:                int64(id),
		Star:               0,
		StarNum:            utils.Int64(lockBlockT.Star.Value),
		Status:             0,
		GridOpenNum:        0,
		Robot:              robot,
		Layers:             make(map[int64]string, 0),
		Monsters:           make(map[int64]map[int64]int64, 0),
		Story:              &m.Story{Tid: int64(lockBlockT.Story), LayerId: storyLayerId},
		TvNum:              utils.Int64(lockBlockT.Tv.Value),
		BombNum:            utils.Int64(lockBlockT.Bomb.Value),
		CrystalballNum:     utils.Int64(lockBlockT.CrystalBall.Value),
		MagicBookRedNum:    utils.Int64(lockBlockT.MagicBookRed.Value),
		MagicBookBlueNum:   utils.Int64(lockBlockT.MagicBookBlue.Value),
		MagicBookPurpleNum: utils.Int64(lockBlockT.MagicBookPurple.Value),
		DriftingBottleNum:  utils.Int64(lockBlockT.DriftingBottle.Value),
	}

	// activFlag := false
	// if _, err := GetCurrentChristmasActivity(); err == nil {
	// 	activFlag = true
	// }
	// if activFlag {
	// 	r.ChristmasBallNum = utils.Int64(lockBlockT.ChristmasBall.Value)
	// 	r.ChristmasCandyNum = utils.Int64(lockBlockT.ChristmasCandy.Value)
	// 	r.ChristmasStockingNum = utils.Int64(lockBlockT.ChristmasStocking.Value)
	// }

	if robot {
		r.RobotLayers = make(map[int64]*m.Layer, 0)
	}

	if oldLockBlock != nil {
		r.Mid = oldLockBlock.Mid
		r.Star = oldLockBlock.Star
		r.Status = oldLockBlock.Status
		if oldLockBlock.Story.Status != 0 {
			r.Story = oldLockBlock.Story
		}
	}

	//	生成的 每层的星星数量
	genStarNum := r.StarNum - r.Star
	//	生成的 关卡电视机数量
	genTvNum := r.TvNum
	//	生成的 关卡炸弹数量
	genBombNum := r.BombNum
	//  生成的 关卡水晶球数量
	genCrystalballNum := r.CrystalballNum
	//  生成的 魔法书红 数量
	genMagicBookRedNum := r.MagicBookRedNum
	//  生成的 魔法书蓝 数量
	genMagicBookBlueNum := r.MagicBookBlueNum
	//  生成的 魔法书紫 数量
	genMagicBookPurpleNum := r.MagicBookPurpleNum
	//  生成的 漂流瓶
	genDriftingBottleNum := r.DriftingBottleNum
	// //  生成的 圣诞装饰球 数量
	// genChristmasBall := r.ChristmasBallNum
	// //  生成的 圣诞拐棍糖 数量
	// genChristmasCandy := r.ChristmasCandyNum
	// //  生成的 圣诞袜 数量
	// genChristmasStocking := r.ChristmasStockingNum

	// 生成每一层怪物数量信息
	mLayersIds := make(map[int64]int64, 0)
	layerNum := layerLen
	dataLayerMaxId := int64(math.MaxInt64)
	for _, layerT := range layersTList {
		layerTId := int64(layerT.Id)
		mLayersIds[layerTId] = layerTId
		if layerTId < dataLayerMaxId {
			// 用于新手大地鼠层位置
			dataLayerMaxId = layerTId
		}
	}
	nGuide := us.GetNewGuide()
	for _, itemMonster := range lockBlockT.Monsters {
		layerSum := int64(layerNum)
		monsterNum := utils.Int64(itemMonster.Value)
		layerNum := 1
		monsterTid := utils.Int64(itemMonster.Key)
		// 如果该怪是新手怪，大地鼠
		if monsterTid == data.NewGuildMonsterTid {
			// 可以过滤掉地鼠人
			if !nGuide.FirstCardMonsterGold {
				r.Monsters[dataLayerMaxId] = map[int64]int64{monsterTid: 1}
			}
		} else if monsterNum < int64(len(mLayersIds)) {
			// 如果怪物数量少于 层级数量
			for lid, _ := range mLayersIds {
				if monsterNum <= 0 {
					break
				}
				if lmonster, ok := r.Monsters[lid]; ok {
					lmonster[monsterTid] = 1
				} else {
					r.Monsters[lid] = map[int64]int64{monsterTid: 1}
				}
				monsterNum -= 1
			}
		} else {
			for lid, _ := range mLayersIds {
				if monsterNum <= 0 {
					break
				}
				// 每层的最多怪物 生成数量
				layerMonsterNum := monsterNum/layerSum + utils.RandomInt64(0, monsterNum%layerSum)
				if len(mLayersIds) == layerNum {
					layerMonsterNum = monsterNum

				}
				if lmonster, ok := r.Monsters[lid]; ok {
					lmonster[monsterTid] = layerMonsterNum
				} else {
					r.Monsters[lid] = map[int64]int64{monsterTid: layerMonsterNum}
				}
				monsterNum -= layerMonsterNum
				layerNum += 1
				layerSum -= 1
			}
		}
	}

	arrStar := utils.GenerateGroupNum(layerLen, genStarNum)                       //预生成星星
	arrBomb := utils.GenerateGroupNum(layerLen, genBombNum)                       //预生成炸弹
	arrTv := utils.GenerateGroupNum(layerLen, genTvNum)                           //预生成电视机
	arrCrystalball := utils.GenerateGroupNum(layerLen, genCrystalballNum)         //预生成许愿球
	arrMagicBookRed := utils.GenerateGroupNum(layerLen, genMagicBookRedNum)       //预生成魔法书红
	arrMagicBookBlue := utils.GenerateGroupNum(layerLen, genMagicBookBlueNum)     //预生成魔法书蓝
	arrMagicBookPurple := utils.GenerateGroupNum(layerLen, genMagicBookPurpleNum) //预生成魔法书紫
	arrDriftingBottle := utils.GenerateGroupNum(layerLen, genDriftingBottleNum)   //预生漂流瓶

	// var arrChristmasBall []int64
	// var arrChristmasCandy []int64
	// var arrChristmasStocking []int64
	// if activFlag {
	// 	arrChristmasBall = utils.GenerateGroupNum(layerLen, genChristmasBall)         //预生成圣诞装饰球
	// 	arrChristmasCandy = utils.GenerateGroupNum(layerLen, genChristmasCandy)       //预生成圣诞拐棍糖
	// 	arrChristmasStocking = utils.GenerateGroupNum(layerLen, genChristmasStocking) //预生成圣诞袜
	// }

	i := -1
	for _, layerT := range layersTList {
		layer := &m.Layer{Tid: int64(layerT.Id), Id: int64(layerT.LayerId), Robot: robot, Mid: bson.NewObjectId().Hex(), Uid: uid}
		// 复用旧的层级id
		if oldLockBlock != nil {
			layer.Mid = oldLockBlock.Layers[int64(layerT.LayerId)]
		}

		// 需要生成 故事绘本
		if storyLayerTid == int64(layerT.Id) {
			layer.StoryGridIds = make([]int64, 0)
			// 找到起始的x 和 y 坐标
			y := utils.RandomInt64(1, 3) - 1
			x := utils.RandomInt64(1, int64(layerT.Column-4))

			column := int64(layerT.Column)

			// 找到故事绘的id
			for y1 := y; y1 < (y + 4); y1++ {
				for x1 := x; x1 < (x + 4); x1++ {
					id := x1 + y1*column - 1
					layer.StoryGridIds = append(layer.StoryGridIds, int64(id))
				}
			}
		}
		if layerT.Layer_type == 0 {
			i++
			layer.StarNum = arrStar[i]               //星星
			layer.BombNum = arrBomb[i]               //炸弹
			layer.TvNum = arrTv[i]                   //电视机
			layer.CrystalballNum = arrCrystalball[i] //许愿球

			layer.MagicBookRedNum = arrMagicBookRed[i]       //魔法书红
			layer.MagicBookBlueNum = arrMagicBookBlue[i]     //魔法书蓝
			layer.MagicBookPurpleNum = arrMagicBookPurple[i] //魔法书紫

			layer.DriftingBottleNum = arrDriftingBottle[i] //漂流瓶

			// if activFlag {
			// 	layer.ChristmasBallNum = arrChristmasBall[i]         //圣诞球
			// 	layer.ChristmasCandyNum = arrChristmasCandy[i]       //圣诞糖
			// 	layer.ChristmasStockingNum = arrChristmasStocking[i] //圣诞袜
			// }

			// 生成祭坛
			if altarNum, ok := mAltarNum[layerT.Id]; ok {
				layer.Altars = generateAltar(altarKindWeights, altarNum, 7, int64(layerT.Column))
			}
		}
		if layerT.LayerId == 1 {
			err := generateLayer(layerT, layer, r)
			if err != nil {
				return nil, err
			}
		}
		if robot {
			r.RobotLayers[int64(layerT.LayerId)] = layer
		} else {
			r.Layers[int64(layerT.LayerId)] = layer.Mid
			// m.Cache.Put("layer", layer.Mid, layer)
			// 更新层信息，并存入数据库
			layer.Update(layer)
		}
	}
	r.GridNum = gridNumSum - int64(len(r.Layers))
	// 更新关卡信息，并存入数据库
	r.Update(r)

	return
}

// 新手引导放火地图 生成机器人关卡
func RobotGenerateFireLockBlock() (layer *m.Layer, err error) {
	lists, ok := data.GetAllDatas("NewGuideFireMaps")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "未找到NewGuideFireMaps")
		return
	}

	layer = &m.Layer{Tid: 1, Id: 1, InGridId: -1}
	layer.GridList = make(map[int64]*m.GridInfo, 0)
	for _, item := range lists {
		grid := item.(data.FirstLayer)
		g := &m.GridInfo{
			Id:     int64(grid.Gid),
			Tid:    int64(grid.Gtid),
			Status: 1,
		}
		if grid.Gtid == 0 {
			g.Status = 0
		}
		if grid.GoodsId != 0 {
			g.Goods = &m.Goods{
				Tid: int64(grid.GoodsId),
				Num: 1,
			}
		}
		layer.GridList[int64(grid.Gid)] = g
	}
	return
}

// 机器人 生成关卡信息
func RobotGenerateLockBlock(uid string, id uint64, oldLockBlock *m.LockBlock, robot bool) (r *m.LockBlock, rl *m.Layer, err error) {
	// 生成关卡祭坛
	altarMessageTpl, ok := data.Get("AltarMessages", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到祭坛配置表,id:%d", id))
		return
	}
	altarMessageT := altarMessageTpl.(data.AltarMessage)

	altarKindList, ok := data.GetAllDatas("AltarKinds")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到祭坛类别信息")
		return
	}

	checkInAltarTypes := func(id uint64, ids []uint64) bool {
		for _, item := range ids {
			if id == item {
				return true
			}
		}
		return false
	}

	var altarKindWeights []data.WeightV

	for _, item := range altarKindList {
		itemv := item.(data.AltarKind)
		if checkInAltarTypes(itemv.Type, altarMessageT.AltarTypes) && itemv.Status == 0 {
			altarKindWeights = append(altarKindWeights, data.WeightV{Weight: itemv.Weight, Value: itemv})
		}
	}

	var layersTList []data.Layer //关卡所有层级

	layerId := 1
	for {
		layerT, ok := getLayerT(uint64(id), uint64(layerId))
		if !ok {
			break
		}
		layersTList = append(layersTList, layerT)
		layerId++
	}
	var gridNumSum int64 = 0

	mGridNum := make(map[uint64][]int64, 0) //可以生成的祭坛随机数组
	for _, layerT := range layersTList {
		gridNum := 7 * layerT.Column
		gridNumSum += int64(gridNum)
		mGridNum[layerT.Id] = []int64{1, 0}
	}

	lockBlockTpl, ok := data.Get("LevelDoors", uint64(id))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到关卡配置表,id:%d", id))
		return
	}
	lockBlockT := lockBlockTpl.(data.LevelDoor)

	var (
		storyLayerTindex int64 = 0
		storyLayerTid    int64 = 0
		storyLayerId     int64 = 0
	)

	// 找到需要生成绘本的 层信息   旧关卡不存在  或者旧关卡的故事绘本 没有集齐
	if lockBlockT.Story > 0 && (oldLockBlock == nil || oldLockBlock.Status == 0) {
		storyLayerTindex = utils.RandomInt64(0, int64(len(layersTList)-1))
		storyLayerTid = int64(layersTList[storyLayerTindex].Id)     // 索引id
		storyLayerId = int64(layersTList[storyLayerTindex].LayerId) // 第几层
	}

	mAltarNum := make(map[uint64]int64, 0) //具体生成祭坛随机数组

	// 先随机生成一波祭坛数据
	var altarSum int64 = 0
	for id, list := range mGridNum {
		if storyLayerTid == int64(id) { // 如果是 故事绘， 不生成祭坛
			continue
		}
		num := utils.RandomInt64(0, int64(len(list))-1)
		if num == 0 {
			continue
		}
		altarSum += num
		if altarSum > int64(altarMessageT.AltarNum) {
			break
		}
		mAltarNum[id] = num
	}

	for id, _ := range mAltarNum {
		delete(mGridNum, id)
	}
	// 补充生成祭坛  直接range map  补充数据
	lessAltarNum := int64(altarMessageT.AltarNum) - altarSum
	for id, list := range mGridNum {
		if lessAltarNum <= 0 {
			break
		}
		if storyLayerTid == int64(id) { // 如果是 故事绘， 不生成祭坛
			continue
		}

		num := len(list) - 1
		if lessAltarNum < int64(num) {
			num = 1
		}
		mAltarNum[id] = int64(num)
		lessAltarNum -= int64(num)
	}

	r = &m.LockBlock{
		Mid:                bson.NewObjectId().Hex(),
		Uid:                uid,
		Tid:                int64(id),
		Star:               0,
		StarNum:            utils.Int64(lockBlockT.Star.Value),
		Status:             0,
		GridOpenNum:        0,
		Robot:              robot,
		Layers:             make(map[int64]string, 0),
		Monsters:           make(map[int64]map[int64]int64, 0),
		Story:              &m.Story{Tid: int64(lockBlockT.Story), LayerId: storyLayerId},
		TvNum:              utils.Int64(lockBlockT.Tv.Value),
		BombNum:            utils.Int64(lockBlockT.Bomb.Value),
		CrystalballNum:     utils.Int64(lockBlockT.CrystalBall.Value),
		MagicBookRedNum:    utils.Int64(lockBlockT.MagicBookRed.Value),
		MagicBookBlueNum:   utils.Int64(lockBlockT.MagicBookBlue.Value),
		MagicBookPurpleNum: utils.Int64(lockBlockT.MagicBookPurple.Value),
	}

	r.RobotLayers = make(map[int64]*m.Layer, 0)

	if oldLockBlock != nil {
		r.Mid = oldLockBlock.Mid
		r.Star = oldLockBlock.Star
		r.Status = oldLockBlock.Status
		if oldLockBlock.Story.Status != 0 {
			r.Story = oldLockBlock.Story
		}
	}

	//	生成的 每层的星星数量
	genStarNum := r.StarNum - r.Star
	//	生成的 关卡电视机数量
	genTvNum := r.TvNum
	//	生成的 关卡炸弹数量
	genBombNum := r.BombNum
	//  生成的 关卡水晶球数量
	genCrystalballNum := r.CrystalballNum
	//  生成的 魔法书-红 数量
	genMagicBookRedNum := r.MagicBookRedNum
	//  生成的 魔法书-蓝 数量
	genMagicBookBlueNum := r.MagicBookBlueNum
	//  生成的 魔法书-紫 数量
	genMagicBookPurpleNum := r.MagicBookPurpleNum

	// 生成每一层怪物数量信息
	mLayersIds := make(map[int64]int64, 0)
	layerLen := GetLayerNumCanGenerateItem(layersTList)
	layerNum := layerLen
	for _, layerT := range layersTList {
		mLayersIds[int64(layerT.Id)] = int64(layerT.Id)
	}

	for _, itemMonster := range lockBlockT.Monsters {
		layerSum := int64(layerNum)
		monsterNum := utils.Int64(itemMonster.Value)
		layerNum := 1
		monsterTid := utils.Int64(itemMonster.Key)
		if monsterNum < int64(len(mLayersIds)) {
			// 如果怪物数量少于 层级数量
			for lid, _ := range mLayersIds {
				if monsterNum <= 0 {
					break
				}
				if lmonster, ok := r.Monsters[lid]; ok {
					lmonster[monsterTid] = 1
				} else {
					r.Monsters[lid] = map[int64]int64{monsterTid: 1}
				}
				monsterNum -= 1
			}
		} else {
			for lid, _ := range mLayersIds {
				if monsterNum <= 0 {
					break
				}
				// 每层的最多怪物 生成数量
				layerMonsterNum := monsterNum/layerSum + utils.RandomInt64(0, monsterNum%layerSum)
				if len(mLayersIds) == layerNum {
					layerMonsterNum = monsterNum
				}
				if lmonster, ok := r.Monsters[lid]; ok {
					lmonster[monsterTid] = layerMonsterNum
				} else {
					r.Monsters[lid] = map[int64]int64{monsterTid: layerMonsterNum}
				}
				monsterNum -= layerMonsterNum
				layerNum += 1
				layerSum -= 1
			}
		}
	}

	arrStar := utils.GenerateGroupNum(layerLen, genStarNum)                       //预生成星星
	arrBomb := utils.GenerateGroupNum(layerLen, genBombNum)                       //预生成炸弹
	arrTv := utils.GenerateGroupNum(layerLen, genTvNum)                           //预生成电视机
	arrCrystalball := utils.GenerateGroupNum(layerLen, genCrystalballNum)         //预生成许愿球
	arrMagicBookRed := utils.GenerateGroupNum(layerLen, genMagicBookRedNum)       //预生成魔法书红
	arrMagicBookBlue := utils.GenerateGroupNum(layerLen, genMagicBookBlueNum)     //预生成魔法书蓝
	arrMagicBookPurple := utils.GenerateGroupNum(layerLen, genMagicBookPurpleNum) //预生成魔法书紫

	i := -1
	for _, layerT := range layersTList {
		layer := &m.Layer{Tid: int64(layerT.Id), Id: int64(layerT.LayerId), Robot: robot, Mid: bson.NewObjectId().Hex(), Uid: uid}
		// 复用旧的层级id
		if oldLockBlock != nil {
			layer.Mid = oldLockBlock.Layers[int64(layerT.LayerId)]
		}

		// 需要生成 故事绘本
		if storyLayerTid == int64(layerT.Id) {
			layer.StoryGridIds = make([]int64, 0)
			// 找到起始的x 和 y 坐标
			y := utils.RandomInt64(1, 3) - 1
			x := utils.RandomInt64(1, int64(layerT.Column-4))

			column := int64(layerT.Column)

			// 找到故事绘的id
			for y1 := y; y1 < (y + 4); y1++ {
				for x1 := x; x1 < (x + 4); x1++ {
					id := x1 + y1*column - 1
					layer.StoryGridIds = append(layer.StoryGridIds, int64(id))
				}
			}
		}

		if layerT.Layer_type == 0 {
			i++
			layer.StarNum = arrStar[i]                       //星星
			layer.BombNum = arrBomb[i]                       //炸弹
			layer.TvNum = arrTv[i]                           //电视机
			layer.CrystalballNum = arrCrystalball[i]         //许愿球
			layer.MagicBookRedNum = arrMagicBookRed[i]       //魔法书红
			layer.MagicBookBlueNum = arrMagicBookBlue[i]     //魔法书蓝
			layer.MagicBookPurpleNum = arrMagicBookPurple[i] //魔法书紫

			// 生成祭坛
			if altarNum, ok := mAltarNum[layerT.Id]; ok {
				layer.Altars = generateAltar(altarKindWeights, altarNum, 7, int64(layerT.Column))
			}
		}
		if layerT.LayerId == 1 {
			err := generateLayer(layerT, layer, r)
			if err != nil {
				return nil, nil, err
			}
		}
		r.RobotLayers[int64(layerT.LayerId)] = layer
	}
	r.GridNum = gridNumSum - int64(len(r.Layers))

	// 获取当前层信息
	rl = r.RobotLayers[1]
	return
}

// 生成格子 无物品
func generateGrid(id uint64) (g *m.GridInfo, gridT data.Brick, err error) {
	gridTpl, ok := data.Get("Bricks", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到对应的格子,id:"+fmt.Sprintf("%d", id))
		return
	}
	gridT = gridTpl.(data.Brick)
	g = &m.GridInfo{
		Tid:    int64(gridT.Id),
		Status: 1,
	}
	return
}

// 生成格子物品
func generateGridGoods(gridT data.Brick) (r *m.Goods) {
	w := utils.RandomWeightKV(gridT.Rewards)
	id := utils.Int64(w.Key)
	num := utils.Int64(w.Value)
	if id == 0 {
		return
	}
	r = &m.Goods{
		Tid: id,
		Num: num,
	}
	return
}

//获取关卡的第一层配置信息
func getLockDoorFirstLayer(id uint64) (r data.Layer, ok bool) {
	return getLayerT(id, 1)
}

// 是否是当前关卡最后一层
func isLastLockDoorLayer(levelDoorId, layerId uint64) (r bool) {
	_, ok := getLayerT(levelDoorId, layerId+1)
	r = !ok
	return
}

// 获取层配置信息
func getLayerT(levelDoorId, layerId uint64) (r data.Layer, ok bool) {
	f := func(val interface{}) bool {
		layerT := val.(data.Layer)
		if layerT.LevelDoorId == levelDoorId && layerT.LayerId == layerId {
			return true
		}
		return false
	}
	val, ok := data.Foreach("Layers", f)
	if !ok {
		return
	}
	r = val.(data.Layer)
	return
}

func getLayerTByTid(tid uint64) (r data.Layer, ok bool) {
	val, ok := data.Get("Layers", tid)
	if !ok {
		return
	}
	r = val.(data.Layer)
	return
}

//计算关卡打开的格子数
func caculLockBlockOpenGridNum(lockBlock *m.LockBlock) {
	var openNum int64 = 0
	var layerNum int64 = 0
	for _, layerMid := range lockBlock.Layers {
		layer, ok := lockBlock.GetLayerByMid(layerMid)
		if !ok {
			continue
		}
		for _, grid := range layer.GridList {
			if grid.Status == 0 {
				openNum++
			}
		}
		if layer.GridList != nil && len(layer.GridList) > 0 {
			layerNum++
		}
	}
	lockBlock.GridOpenNum = openNum - layerNum
}

// 刷新当前层
func RefreshLayer(u *m.User) (rlayer *m.Layer, err error) {
	layer := u.GetLayer()
	err = generateLayer2(layer, u.GetCurrentLockBlock())
	return
}

// 获取当前的层级
func CurrentLayer(u *m.User) (layer *m.Layer) {
	return u.GetLayer()
}

// 获取上一层
func PreLayer(u *m.User) (layer *m.Layer, err error) {
	return u.PreLayer()
}

// 获取下一层数据
func NextLayer(u *m.User) (layer *m.Layer, err error) {
	nLayer, ok := u.NextLayer()
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到下一层，关卡：%d, 层:%d", u.Pos.LockBlockTid, u.Pos.LayerId))
		return
	}

	if nLayer.GridList == nil || len(nLayer.GridList) == 0 {
		err = generateLayer2(nLayer, u.GetCurrentLockBlock())
		if err != nil {
			return
		}
	}

	layer = nLayer
	layer.IsFirstIn = 1
	layer.Update(layer)
	return
}

// 刷新当前关卡
// 放弃当前关卡
func RefreshCurrentLockBlock(u *m.User) (r *m.LockBlock, uProp *m.UpdateProp, err error) {
	r = u.GetCurrentLockBlock()
	lockBlock := u.GetCurrentLockBlock()
	r, err = GenerateLockBlock(u, uint64(lockBlock.Tid), lockBlock, u.Robot)
	if err != nil {
		return
	}
	// if lockBlock.Num < 1 {
	// 	uProp = &m.UpdateProp{Kvs: []*m.BaseKV{&m.BaseKV{Key: data.GlobalEnum.Star, Val: -lockBlock.Star}}}
	// 	lockBlock.Star = 0
	// }
	r.Num = lockBlock.Num
	u.SetCurrentLockBlock(r)
	return
}

// 前一关
func PreLockBlock(u *m.User) (r *m.LockBlock, err error) {
	r, err = u.PreLockBlock()
	if err != nil {
		return
	}
	// if r.Layers == nil || len(r.Layers) == 0 {
	// 	nr, err := GenerateLockBlock(u.Uid.Hex(), uint64(r.Tid), r, u.Robot)
	// 	if err != nil {
	// 		return nil, err
	// 	}
	// 	r.Layers = nr.Layers
	// }

	// 移动关卡，都重新生成当前关信息。
	nr, err := GenerateLockBlock(u, uint64(r.Tid), r, u.Robot)
	if err != nil {
		return nil, err
	}
	r.Layers = nr.Layers
	return
}

// 下一关
func NextLockBlock(u *m.User) (r *m.LockBlock, err error) {
	nLockBlock, ok := UserNextLockBlock(u)
	// if ok {
	// 	r = nLockBlock
	// 	if r.Layers == nil || len(r.Layers) == 0 {
	// 		nr, err := GenerateLockBlock(u.Uid.Hex(), uint64(r.Tid), nLockBlock, u.Robot)
	// 		if err != nil {
	// 			return nil, err
	// 		}
	// 		r.Layers = nr.Layers
	// 	}
	// 	return
	// }

	// 有旧的关卡，重新分配资源。
	if nLockBlock != nil {
		r, err = GenerateLockBlock(u, uint64(nLockBlock.Tid), nLockBlock, u.Robot)
		if err != nil {
			return nil, err
		}
		return r, nil
	}

	// 如果没有旧的关卡，重新生成关卡并分配资源。
	nLockBlockTid := u.Pos.LockBlockTid + 1
	rLockBlock, err := GenerateLockBlock(u, uint64(nLockBlockTid), nil, u.Robot)
	if err != nil {
		return
	}

	u.AddLockBlock(rLockBlock)
	nLockBlock, ok = UserNextLockBlock(u)
	if !ok {
		err = errors.NewErrcode(12, "获取下一关卡数据失败")
		return
	}
	r = nLockBlock
	return
}

// 关卡移动
// id 关卡id
func MoveLockBlock(u *m.User, id int64) (r *m.LockBlock, err error) {
	r, ok := u.GetLockBlock(id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NotFound, fmt.Sprintf("没有找到关卡:%d", id))
		return
	}
	// if r.Layers == nil || len(r.Layers) == 0 {
	// 	nr, err := GenerateLockBlock(u.Uid.Hex(), uint64(id), r, u.Robot)
	// 	if err != nil {
	// 		return nil, err
	// 	}
	// 	r.Layers = nr.Layers
	// }

	// 移动关卡，都重新生成当前关信息。
	nr, err := GenerateLockBlock(u, uint64(id), r, u.Robot)
	if err != nil {
		return nil, err
	}
	r.Layers = nr.Layers
	u.MoveLockBlock(id)
	return
}

// 用户移动下一关，需要计算最大关卡
func UserNextLockBlock(u *m.User) (r *m.LockBlock, ok bool) {
	nextTid := u.Pos.LockBlockTid + 1
	if v, ok := u.GetLockBlock(nextTid); ok {
		defer u.Update(u)
		u.Pos.LockBlockTid = nextTid
		u.Pos.LayerId = 1
		if u.Pos.LockBlockTid >= u.MaxPos.LockBlockTid {
			// 设置最大关卡
			u.MaxPos.LockBlockTid = u.Pos.LockBlockTid
			u.MaxPos.LayerId = 1

			// 成就，抵达关卡
			AchievArrivallevel(u)
		}
		u.ResetCurrentLayerOpenGridNum()
		return v, true
	}
	return
}

// 层级移动
// id 为层id
func MoveLayer(u *m.User, id int64) (r *m.Layer, err error) {
	if id == 0 {
		err = errors.NewErrcode(data.Errcode.NotFound, fmt.Sprintf("没有找到层级:%d", id))
		return
	}
	// 获取当前关卡
	lockBlock := u.GetCurrentLockBlock()
	// 获取层
	r, ok := lockBlock.GetLayer(id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NotFound, fmt.Sprintf("没有找到层级:%d", id))
		return
	}
	u.MoveLayer(id)
	return
}

// 检出该成是否完成
func CheckLayerDone(layer *m.Layer) (r bool) {
	for _, grid := range layer.GridList {
		if grid.Status != 0 {
			return false
		}
	}
	return true
}

// 检查关卡是否完成
func CheckLockBlockDone(lockBlock *m.LockBlock) (r bool) {
	for _, layerMid := range lockBlock.Layers {
		layer, ok := lockBlock.GetLayerByMid(layerMid)
		if !ok {
			return false
		}
		if layer.Status == 0 {
			return false
		}
	}
	return true
}

// 获取焦土格子tid
func getFireGridTid(layerT data.Layer) (r int64) {
	for _, gridw := range layerT.Grids {
		if utils.Int64(gridw.Weight) == 0 { // 配表中，weight为0，表示焦土。
			r = utils.Int64(gridw.Value) // 说明是焦土
			break
		}
	}
	return
}

// 开格子
// Param gridId 格子id
// Param u 玩家信息
// Param free 是否免费
// return rGrids 影响到的格子信息  isFireGrid 是否是防火格子  openAltar 祭坛开启  uProp 资源变更  openGridNum 开启的格子数  storyStatus 故事绘本状态
func OpenGrid(gridId int64, u *m.User, free bool, bombFlag bool) (rGrids map[int64]*m.GridInfo, isFireGrid, openAltar bool, uProp *m.UpdateProp, openGridNum int64, storyStatus int64, lockBrick bool, err error) {
	gridInfo, ok := u.GetGrid(gridId)
	// 格子锁住，并且不是炸弹
	if gridInfo.StatusEx == 1 && !bombFlag {
		lockBrick = true
		return
	}

	if !ok {
		err = errors.NewErrcode(data.Errcode.NoGrid, "没有找到该格子")
		return
	}

	if gridInfo.Status <= 0 {
		err = errors.NewErrcode(data.Errcode.GridIsOpen, "格子已经被翻开")
		return
	}

	lockBlock := u.GetCurrentLockBlock()

	layer := u.GetLayer()
	layerT, ok := getLayerTByTid(uint64(layer.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到层配置")
		return
	}
	// 更新关卡信息
	defer lockBlock.Update(lockBlock)
	// 更新层信息
	defer layer.Update(layer)
	fireGridTid := getFireGridTid(layerT)
	isFireGrid = (gridInfo.Tid == fireGridTid)
	var cost m.BaseKV
	for _, item := range layerT.Costs {
		if item.BrickId == uint64(gridInfo.Tid) {
			cost = m.BaseKV{Key: int64(item.Key), Val: int64(item.Val)}
			if isFireGrid {
				cost.Val = cost.Val - int64(float64(cost.Val)*float64(u.FireGridRate)/float64(100))
			}
			break
		}
	}

	if !free {
		// 扣开箱子金币前，检查是否有影响的因素
		scryerInfo := u.GetScryerInfoData()
		if scryerInfo != nil {
			scryBuff, findBuff := scryerInfo.ScryBuffGet(data.ScryBuffEnum.Treasure)
			if findBuff == true && scryBuff != nil {
				// 修改 cost
				cost.Val = int64((float64(cost.Val) * scryBuff.Val))
				// 修改 buff
				scryBuff.LeftCount = (scryBuff.LeftCount - 1)
				scryerInfo.ScryBuffUpsetAndUpdate(scryBuff)
			}
		}

		uProp, err = Cost("OpenGrid", u, []m.BaseKV{cost})
		if err != nil {
			return
		}

		// 委托活动，打开格子消耗金币。
		CalcHonor(u, data.EntrType.Dwarf, data.EntrEnum.OpenGrid, u.Pos.LockBlockTid)
	}

	rGrids = make(map[int64]*m.GridInfo, 0)
	gridInfo.Status--
	if gridInfo.ExtId != 0 {
		gridInfo.Tid = gridInfo.ExtId
		gridInfo.ExtId = 0
	}
	gridInfo.Head = ""
	gridInfo.AvatarFrame = 0

	rGrids[gridId] = gridInfo

	if gridInfo.Status == 0 {
		u.Pos.LayerOpenGridNum++
		lockBlock.GridOpenNum += 1
		if lockBlock.GridOpenNum == lockBlock.GridNum {
			//lockBlock.Star++
			//uProp.Kvs = append(uProp.Kvs, &m.BaseKV{Key: data.GlobalEnum.Star, Val: 1})
			if lockBlock.Status < 1 {
				lockBlock.Status++ // 通关
			}
			lockBlock.Num++
		}
	}

	// 检查绘本是否完成
	getStoryStatus := func(storyIds []int64) int64 {
		for _, gid := range storyIds {
			grid := layer.GetGrid(gid)
			if grid.Status != 0 {
				return 0
			}
		}
		return 1
	}

	if len(layer.StoryGridIds) > 0 && lockBlock.Story != nil && lockBlock.Story.Status == 0 {
		lockBlock.Story.Status = getStoryStatus(layer.StoryGridIds)
		storyStatus = lockBlock.Story.Status
	}

	// 检查祭坛是否 完成
	checkAltar := func(altarGridIds []int64) bool {
		for _, gid := range altarGridIds {
			grid := layer.GetGrid(gid)
			if grid.Status != 0 {
				return false
			}
		}
		return true
	}

	if layer.Altars != nil && len(layer.Altars) > 0 {
		for _, altar := range layer.Altars {
			if altar.Status != 0 {
				continue
			}
			// 激活祭坛
			if checkAltar(altar.GridIds) {
				u.GetUserStatic().AddTypNum(data.StaticTYP.Altar, 1)
				altar.Status = 1
				openAltar = true
				altarT := mAltarT[altar.Typ]
				for _, gid := range altar.GridIds {
					grid := layer.GetGrid(gid)
					grid.Goods = &m.Goods{Tid: altarT.goodsIngTid, Num: 1}
					rGrids[gid] = grid
				}
			}
		}
	}
	openGridNum = lockBlock.GridOpenNum

	// 成就，记录连续打开的格子数
	AchievAuxiliAddCOG(u, 1)
	return
}

//使用格子的物品
func UseGridGoods(gridId int64, u *m.User, PSend func(interface{}) error) (goodsTid int64, r map[int64]*m.GridInfo, uProp *m.UpdateProp, resGoods []*m.Goods, boxResList []*m.BoxRes, err error) {
	gridInfo, ok := u.GetGrid(gridId)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoGrid, "没有找到该格子")
		return
	}
	if gridInfo.Status != 0 {
		err = errors.NewErrcode(data.Errcode.GridNoOpen, "格子没有被翻开")
		return
	}
	if gridInfo.Goods == nil {
		err = errors.NewErrcode(data.Errcode.GridNoGoods, "没有物品")
		return
	}

	goodsTpl, ok := data.Get("Goods", uint64(gridInfo.Goods.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到该物品配置")
		return
	}

	r = make(map[int64]*m.GridInfo, 0)
	r[gridId] = gridInfo

	// 更新层级信息
	defer u.GetLayer().UpdateGridByMap(r)
	// 如果物品是钥匙
	goodsTid = gridInfo.Goods.Tid
	if gridInfo.Goods.Tid == keyGoods.Tid {
		for id, grid := range u.GetLayer().GridList {
			if grid.Goods == nil {
				continue
			}
			if grid.Goods.Tid == closeDoorGoods.Tid { //改变门状态
				if grid.Status != 0 {
					err = errors.NewErrcode(data.Errcode.NotFoundDoor, "门未被挖开")
					return 0, nil, nil, nil, nil, err
				}
				openDoorGoods1 := openDoorGoods
				grid.Goods = &openDoorGoods1
				r[id] = grid
				break
			}
		}
		gridInfo.Goods = nil
		return
	}

	// 如果物品是星星
	if gridInfo.Goods.Tid == starGoods.Tid {

		lockBlock := u.GetCurrentLockBlock()
		lockBlock.Star++
		uProp = m.NewUpdateProp()
		uProp.Kvs = append(uProp.Kvs, &m.BaseKV{Key: data.GlobalEnum.Star, Val: 1})
		gridInfo.Goods = nil
		// 更新关卡信息
		lockBlock.Update(lockBlock)
		u.LockBlocks().UpdateLockBlock(lockBlock)

		//统计地图星星
		SumMapStar(u)
		// 成就，记录获取星星数量。
		AddAchievProgress(u, data.AchievementType.Get_stars, u.StarVal())
		// 计算新兵特训
		RecruitTrainMsg(u.Uid.Hex(), 0, u.StarSum, 0, PSend)
		return
	}

	goodsT := goodsTpl.(data.Good)

	if int64(goodsT.Category) == data.GoodsCategoryEnum.CategoryLv1 {
		err = errors.NewErrcode(data.Errcode.ServerErr, "该物品是祭坛，不可以使用")
		return
	}
	// 收集活动道具
	if int64(goodsT.Category) == data.GoodsCategoryEnum.CategoryLv6 {
		if data.GoodsTypeEnum.ChristmasBall == int64(goodsT.Type) ||
			data.GoodsTypeEnum.ChristmasCandy == int64(goodsT.Type) ||
			data.GoodsTypeEnum.ChristmasStocking == int64(goodsT.Type) {
			AddGoodChristmasTree(u, int64(goodsT.Type), gridInfo.Goods.Num, PSend)
			resGoods = append(resGoods, &m.Goods{
				Tid: gridInfo.Goods.Tid,
				Num: gridInfo.Goods.Num,
			})
			gridInfo.Goods = nil
			return
		}
	}
	// 收集活动道具
	if int64(goodsT.Category) == data.GoodsCategoryEnum.CategoryLv12 {
		AddGoodColloctProp(u, goodsT, gridInfo.Goods.Num, PSend)
		resGoods = append(resGoods, &m.Goods{
			Tid: gridInfo.Goods.Tid,
			Num: gridInfo.Goods.Num,
		})
		gridInfo.Goods = nil
		return
	}

	uProp, resGoods, boxResList, err = UseGood("UseGridGoods", u, goodsT, PSend)
	if err != nil {
		return
	}
	// 成就，拾取地图上的箱子
	if int64(goodsT.Category) == data.GoodsCategoryEnum.CategoryLv3 {
		AddAchievProgress(u, data.AchievementType.Get_chest, 1)
	}
	// 成就，拾取地图上的金币次数
	if int64(goodsT.Category) == data.GoodsCategoryEnum.CategoryLv5 {
		AddAchievProgress(u, data.AchievementType.Pick_gold, 1)
	}
	gridInfo.Goods = nil
	return
}

// 关卡奖励
func LockBlockReward(from string, u *m.User, id int64, PSend func(interface{}) error) (uProp *m.UpdateProp, resGoodsList []*m.Goods, BoxResList []*m.BoxRes, err error) {
	lockBlock, ok := u.GetLockBlock(id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NotFound, fmt.Sprintf("没有找到关卡信息id：%d", id))
		return
	}

	if lockBlock.Star != lockBlock.StarNum {
		err = errors.NewErrcode(data.Errcode.LevelDoorUndone, "未收集满所有星星")
		return nil, nil, nil, err
	}

	if lockBlock.Status > 1 {
		err = errors.NewErrcode(data.Errcode.LevelDoorRec, "奖励已经领取")
		return nil, nil, nil, err
	}

	if lockBlock.Num > 1 {
		err = errors.NewErrcode(data.Errcode.LevelDoorUndone, "关卡二次奖励，已取消")
		return nil, nil, nil, err
	}

	lockBlockTpl, ok := data.Get("LevelDoors", uint64(id))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到关卡配置表,id:%d", id))
		return
	}
	lockBlockT := lockBlockTpl.(data.LevelDoor)

	var rewards []m.BaseKV

	defer lockBlock.Update(lockBlock)
	// if lockBlock.Num > 1 {
	// 	for _, item := range lockBlockT.Rewards2 {
	// 		rewards = append(rewards, m.BaseKV{Key: int64(item.Key), Val: utils.Int64(item.Value)})
	// 	}
	// }

	// if lockBlock.Num == 1 {
	for _, item := range lockBlockT.Rewards {
		rewards = append(rewards, m.BaseKV{Key: int64(item.Key), Val: utils.Int64(item.Value)})
	}
	// }

	uProp, resGoodsList, BoxResList, err = GiveGoodsByKvList(from, u, rewards, PSend)
	if err != nil {
		return
	}

	lockBlock.Status = 2
	return
}

// 获取层祭坛  通过格子id
func GetLayerAltarByGridId(list []*m.Altar, gid int64) (r *m.Altar, ok bool) {
	checkInIds := func(id int64, ids []int64) bool {
		for _, item := range ids {
			if id == item {
				return true
			}
		}
		return false
	}

	for _, item := range list {
		if checkInIds(gid, item.GridIds) {
			return item, true
		}
	}
	return nil, false
}

// 获取祭坛奖励
func GetAltarRewards(from string, u *m.User, gid int64, PSend func(interface{}) error) (uProp *m.UpdateProp, op int64, roll int64, resGoodsList []*m.Goods, err error) {
	layer := u.GetLayer()
	altar, ok := GetLayerAltarByGridId(layer.Altars, gid)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到祭坛，格子id,id:%d", gid))
		return
	}
	if altar.Status != 1 && altar.Status != 2 {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("祭坛奖励不可领取，格子id,id:%d status:%d", gid, altar.Status))
		return
	}

	sixDiceList, ok := data.GetAllDatas("AltarSixDices")
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "六面骰子配置获取失败")
		return
	}

	var wDiceList []data.WeightV

	for _, item := range sixDiceList {
		itemv := item.(data.Dice)
		wDiceList = append(wDiceList, data.WeightV{Weight: itemv.Weight, Value: itemv})
	}

	// 获取光看广告信息  检查是否可以免费 获取20面骰子 奖励
	adinfo := u.GetAdRewards()

	adReward := adinfo.GetAdReward(4)

	isCostAdAltarNum := false
	if adReward.AltarNum == 1 {
		isCostAdAltarNum = true
	}

	uProp = m.NewUpdateProp()
	if altar.Status == 2 {
		expandTpl, ok := data.Get("AltarExpands", uint64(1))
		if !ok {
			err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到20面骰子消耗，id:%d", 1))
			return nil, 0, 0, nil, err
		}
		twentyDiceList, ok := data.GetAllDatas("AltarTwentyDices")
		if !ok {
			err = errors.NewErrcode(data.Errcode.ConfigNotFound, "二十面骰子配置获取失败")
			return nil, 0, 0, nil, err
		}
		wDiceList = make([]data.WeightV, 0)

		for _, item := range twentyDiceList {
			itemv := item.(data.Dice)
			wDiceList = append(wDiceList, data.WeightV{Weight: itemv.Weight, Value: itemv})
		}

		expandT := expandTpl.(data.AltarExpand)
		// 不是观看广告获得的摇20面骰子
		if !isCostAdAltarNum {
			uprop1, err := Cost(from, u, []m.BaseKV{{Key: int64(expandT.Expand.Key), Val: utils.Int64(expandT.Expand.Value)}})
			if err != nil {
				return nil, 0, 0, nil, err
			}
			uProp.Merge(uprop1)
		}
		op = 1
	}

	wdice := utils.RandomWeight(wDiceList)
	diceT := wdice.Value.(data.Dice)
	goodsItem, err := getAltarRewards(uint64(u.Pos.LockBlockTid), int64(altar.Typ), int64(diceT.Roll))
	if err != nil {
		return
	}
	roll = int64(diceT.Roll)
	uprop2, resGoodsList, _, err := GiveGoodsByKv(from, u, goodsItem, PSend)
	if err != nil {
		return
	}
	// 更新层信息
	defer layer.Update(layer)

	// 更新观看广告祭坛领取奖励 次数
	if isCostAdAltarNum {
		adinfo.UpdateAdRewardAltarNum(adReward.WatchNum, 0)

		// 成就，记录观看广告
		AddAchievProgress(u, data.AchievementType.Watch_ads, 1)
	}
	uProp.Merge(uprop2)
	altar.Status++
	return
}

// 获取祭坛 具体奖励
// 关卡id  祭坛类型  点数
func getAltarRewards(id uint64, altarType int64, roll int64) (goodsItem m.BaseKV, err error) {
	altarMessageTpl, ok := data.Get("AltarMessages", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到祭坛配置表,id:%d", id))
		return
	}
	altarMessageT := altarMessageTpl.(data.AltarMessage)

	altarKindTpl, ok := data.Foreach("AltarKinds", func(val interface{}) bool {
		val1 := val.(data.AltarKind)
		return int64(val1.Type) == altarType && val1.Status == 1
	})

	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到祭坛类别,altarType:%d", altarType))
		return
	}

	var baseItem m.BaseKV
	altarKindT := altarKindTpl.(data.AltarKind)

	switch int64(altarKindT.RewardType) {
	case data.GlobalEnum.Gold:
		baseItem = m.BaseKV{Key: int64(altarMessageT.GoldStandard.Key), Val: utils.Int64(altarMessageT.GoldStandard.Value)}
	case data.GlobalEnum.Diamond:
		baseItem = m.BaseKV{Key: int64(altarMessageT.DimondStandard.Key), Val: utils.Int64(altarMessageT.DimondStandard.Value)}
	case data.GlobalEnum.Energy:
		baseItem = m.BaseKV{Key: int64(altarMessageT.EnergyStandard.Key), Val: utils.Int64(altarMessageT.EnergyStandard.Value)}
	}

	goodsItem = baseItem
	goodsItem.Val = baseItem.Val * roll
	return
}

// m*n 的矩阵 随机取出一个 3*3矩阵的中心点坐标
func findMapBlock1(mNum, nNum int64) (x, y int64) {
	x = utils.RandomInt64(2, nNum-1)
	y = utils.RandomInt64(2, mNum-1)
	return
}

// m*n 的矩阵 随机取出 2个不重叠的3*3 矩阵的 中心点坐标
func findMapblock2(mNum, nNum int64) (x1, y1, x2, y2 int64) {
	if nNum < 6 && mNum < 6 {
		return
	}
	var (
		yList []int64
		xList []int64
	)
	if nNum == 6 && mNum == 6 {
		x1 = utils.RandomInt64(2, 5)
		if x1 == 3 || x1 == 4 {
			y1 = 2
		} else {
			y1 = utils.RandomInt64(2, 5)
		}

		if x1 == 3 || x1 == 4 {
			x2 = utils.RandomInt64(2, 5)
			y2 = 2
			if y1 == 2 {
				y2 = 5
			}
			return
		}
		if y1 == 3 || y1 == 4 {
			y2 = utils.RandomInt64(2, 5)
			x2 = 2
			if x1 == 2 {
				x2 = 5
			}
			return
		}
	} else if nNum == 7 {
		x1 = utils.RandomInt64(2, nNum-1)
		if x1 == 4 {
			if mNum == 6 {
				yList = []int64{2, 5}
				index := utils.RandomInt64(0, int64(len(yList))-1)
				y1 = yList[index]
			} else if mNum == 7 {
				yList = []int64{2, 3, 5, 6}
				index := utils.RandomInt64(0, int64(len(yList))-1)
				y1 = yList[index]
			} else {
				y1 = utils.RandomInt64(2, mNum-1)
			}

		} else {
			y1 = utils.RandomInt64(2, mNum-1)
		}
	} else if mNum == 7 {
		y1 = utils.RandomInt64(2, mNum-1)
		if y1 == 4 {
			if nNum == 6 {
				xList = []int64{2, 5}
				index := utils.RandomInt64(0, int64(len(xList))-1)
				x1 = xList[index]
			} else if nNum == 7 {
				xList = []int64{2, 3, 5, 6}
				index := utils.RandomInt64(0, int64(len(xList))-1)
				x1 = xList[index]
			} else {
				x1 = utils.RandomInt64(2, nNum-1)
			}
		} else {
			x1 = utils.RandomInt64(2, nNum-1)
		}

	} else {
		x1 = utils.RandomInt64(2, nNum-1)
		y1 = utils.RandomInt64(2, mNum-1)
	}

	xList = make([]int64, 0)
	yList = make([]int64, 0)

	for i := 1; i < int(nNum); i++ {
		if (int64(i) <= x1-3) && (i > 1) || (int64(i) >= x1+3) {
			xList = append(xList, int64(i))
		}
	}

	for i := 1; i < int(mNum); i++ {
		if (int64(i) <= y1-3) && (i > 1) || (int64(i) >= y1+3) {
			yList = append(yList, int64(i))
		}
	}

	if len(xList) == 0 && len(yList) == 0 {
		panic("生成祭坛错误 xlist 与 ylist 都为空")
	}
	if len(xList) > 0 && len(yList) > 0 {
		flag := utils.RandomInt64(0, 1)
		if flag == 0 {
			xList = make([]int64, 0)
		} else {
			yList = make([]int64, 0)
		}
	}

	if len(yList) == 0 {
		xindex := utils.RandomInt64(0, int64(len(xList))-1)
		x2 = xList[xindex]
		y2 = utils.RandomInt64(2, mNum-1)
	}

	if len(xList) == 0 {
		yindex := utils.RandomInt64(0, int64(len(yList))-1)
		y2 = yList[yindex]
		x2 = utils.RandomInt64(2, nNum-1)
	}

	return
}

// 生成祭坛数据
func generateAltar(ts []data.WeightV, num, mNum, nNum int64) (r []*m.Altar) {
	if num == 1 {
		wt := utils.RandomWeight(ts)
		altarKind := wt.Value.(data.AltarKind)
		typ := int(altarKind.Type)
		altarT := mAltarT[typ]
		x, y := findMapBlock1(mNum, nNum)
		x--
		y--
		mMap := generaAtlarGridIdMap(x, y, nNum)
		gridsIds := getAltarGridIds(altarT, mMap)
		r = append(r, &m.Altar{GridIds: gridsIds, Typ: typ})
		return
	}
	if num == 2 {
		x1, y1, x2, y2 := findMapblock2(mNum, nNum)
		x1--
		y1--
		x2--
		y2--
		mMap1 := generaAtlarGridIdMap(x1, y1, nNum)
		mMap2 := generaAtlarGridIdMap(x2, y2, nNum)
		wt := utils.RandomWeight(ts)
		altarKind := wt.Value.(data.AltarKind)
		typ := int(altarKind.Type)

		gridsIds1 := getAltarGridIds(mAltarT[typ], mMap1)
		r = append(r, &m.Altar{GridIds: gridsIds1, Typ: typ})
		wt = utils.RandomWeight(ts)
		altarKind = wt.Value.(data.AltarKind)
		typ = int(altarKind.Type)
		gridsIds2 := getAltarGridIds(mAltarT[typ], mMap2)
		r = append(r, &m.Altar{GridIds: gridsIds2, Typ: typ})
		return
	}
	return
}

func generaAtlarGridIdMap(x, y, nNum int64) (r [3][3]int64) {
	r = [3][3]int64{
		{caclAltarId(x-1, y-1, nNum), caclAltarId(x, y-1, nNum), caclAltarId(x+1, y-1, nNum)},
		{caclAltarId(x-1, y, nNum), caclAltarId(x, y, nNum), caclAltarId(x+1, y, nNum)},
		{caclAltarId(x-1, y+1, nNum), caclAltarId(x, y+1, nNum), caclAltarId(x+1, y+1, nNum)},
	}
	return
}

func getAltarGridIds(altarT altarTpl, mMap [3][3]int64) (r []int64) {
	for i := 0; i < 3; i++ {
		for j := 0; j < 3; j++ {
			id := int64(altarT.data[i][j]) * mMap[i][j]
			if id == 0 {
				if altarT.data[i][j] == 1 {
					r = append(r, id)
				}
				continue
			}
			r = append(r, id)
		}
	}
	return
}

// 计算祭坛所在的格子id
func caclAltarId(x, y, nNum int64) int64 {
	return y*nNum + x
}

type altarTpl struct {
	data        [3][3]int
	goodsTid    int64
	goodsIngTid int64
}

// 6种祭坛
var mAltarT map[int]altarTpl = map[int]altarTpl{
	1: altarTpl{
		data: [3][3]int{
			{0, 1, 0},
			{1, 1, 1},
			{0, 0, 1},
		},
		goodsTid:    150301,
		goodsIngTid: 150302,
	},
	2: altarTpl{
		data: [3][3]int{
			{1, 0, 1},
			{1, 1, 1},
			{1, 0, 1},
		},
		goodsTid:    150303,
		goodsIngTid: 150304,
	},
	3: altarTpl{
		data: [3][3]int{
			{1, 0, 1},
			{0, 1, 0},
			{1, 0, 1},
		},
		goodsTid:    150305,
		goodsIngTid: 150306,
	},
	4: altarTpl{
		data: [3][3]int{
			{1, 0, 1},
			{0, 1, 0},
			{1, 1, 1},
		},
		goodsTid:    150307,
		goodsIngTid: 150308,
	},
	5: altarTpl{
		data: [3][3]int{
			{1, 1, 1},
			{1, 0, 1},
			{1, 1, 1},
		},
		goodsTid:    150309,
		goodsIngTid: 150310,
	},
	6: altarTpl{
		data: [3][3]int{
			{1, 1, 1},
			{1, 1, 1},
			{1, 1, 1},
		},
		goodsTid:    150311,
		goodsIngTid: 150312,
	},
}

//使用炸弹
func UseBomb(gridId int64, u *m.User) (targetGridId int64, gridsNeedToOpen []int64, r map[int64]*m.GridInfo, err error) {
	gridInfo, ok := u.GetGrid(gridId)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoGrid, "没有找到该格子")
		return
	}
	if gridInfo.Status != 0 {
		err = errors.NewErrcode(data.Errcode.GridNoOpen, "格子没有被翻开")
		return
	}
	if gridInfo.Goods == nil {
		err = errors.NewErrcode(data.Errcode.GridNoGoods, "没有物品")
		return
	}
	// 如果物品是炸弹
	if gridInfo.Goods.Tid != bombGoods.Tid {
		err = errors.NewErrcode(data.Errcode.ServerErr, "物品不是炸弹")
		return
	}

	r = make(map[int64]*m.GridInfo, 0)
	r[gridId] = gridInfo
	gridInfo.Goods = nil

	// 更新层级信息
	defer u.GetLayer().UpdateGridByMap(r)
	//如何獲取玩家的關卡數據
	layer := u.GetLayer()
	layerT, ok := getLayerTByTid(uint64(layer.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到层配置")
		return
	}
	gridList := layer.GridList
	gridListLen := int64(len(gridList))
	targetGridId = utils.RandomInt64(0, gridListLen-1)

	column := int64(layerT.Column)
	row := gridListLen / column
	posX := targetGridId % column
	posY := targetGridId / column
	var posXMin int64
	var posXMax int64
	var posYMin int64
	var posYMax int64
	if posX == 0 {
		posXMin = posX
	} else {
		posXMin = posX - 1
	}
	if posX < column-1 {
		posXMax = posX + 1
	} else {
		posXMax = posX
	}
	if posY == 0 {
		posYMin = posY
	} else {
		posYMin = posY - 1
	}
	if posY < row-1 {
		posYMax = posY + 1
	} else {
		posYMax = posY
	}

	var gridInfoTemp *m.GridInfo
	for y1 := posYMin; y1 <= posYMax; y1++ {
		for x1 := posXMin; x1 <= posXMax; x1++ {
			id := y1*column + x1
			gridInfoTemp = gridList[id]
			if gridInfoTemp != nil && gridInfoTemp.Status != 0 {
				gridsNeedToOpen = append(gridsNeedToOpen, id)
			}
		}
	}
	return
}

// 使用漂流瓶
func UseDriftingBottle(gridId int64, us *m.User) (r *m.GridInfo, kvs []m.BaseKV, res []*m.Goods, err error) {
	layer := us.GetLayer()
	gridInfo := layer.GetGrid(gridId)
	if gridInfo.Status != 0 {
		err = errors.NewErrcode(data.Errcode.GridNoOpen, "格子没有被翻开")
		return
	}
	if gridInfo.Goods == nil {
		err = errors.NewErrcode(data.Errcode.GridNoGoods, "没有物品")
		return
	}
	goodTpl, ok := data.Get("Goods", uint64(gridInfo.Goods.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到该物品配置")
		return
	}
	layerT, ok := getLayerT(uint64(us.MaxPos.LockBlockTid), uint64(us.MaxPos.LayerId))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, fmt.Sprintf("没有找到层配置信息:Pos%v", us.MaxPos))
		return
	}
	goodsT := goodTpl.(data.Good)
	if int64(goodsT.Category) != data.GoodsCategoryEnum.CategoryLv6 || int64(goodsT.Type) != data.GoodsTypeEnum.DriftingBottle {
		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("该道具不是漂流瓶%v %v", goodsT.Category, goodsT.Type))
		return
	}
	kvs, res, err = getBoxRewards(utils.Uint64(goodsT.Effect), layerT.Page)
	r = gridInfo
	gridInfo.Goods = nil

	layer.Update(layer)

	return
}

// 计算所有关卡星星和
func SumMapStar(u *m.User) (r int64) {
	lockBlocks := u.LockBlocks()
	r = 0
	for _, item := range lockBlocks.LockBlocks {
		r += item.Star
	}

	u.StarMap = r
	u.Update(u)
	return
}

// 打开的格子有怪，把怪周围8个格子，有砖块的格子锁住
func MonsterLockBrick(u *m.User, grids map[int64]*m.GridInfo) (r map[int64]*m.GridInfo, err error) {
	r = make(map[int64]*m.GridInfo)

	layer := u.GetLayer()
	layerT, ok := getLayerTByTid(uint64(layer.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到层配置")
		return
	}

	col := int64(layerT.Column) // 列
	row := int64(len(layer.GridList)) / col

	//记录怪周围的格子id
	mGridId := make(map[int64]int64)
	for key, val := range grids {
		r[key] = val // 先拷贝一遍
		// 格子中状态为0，表示无砖块，无焦土
		// 格子中的道具是怪
		if val.Status == 0 &&
			val.Goods != nil &&
			IsMonster(val.Goods.Tid) {
			// 计算周围8个格子id
			posCol := val.Id % col
			posRow := val.Id / col
			for posColT := posCol - 1; posColT <= posCol+1; posColT++ {
				for posRowT := posRow - 1; posRowT <= posRow+1; posRowT++ {
					// 越界 不做计算
					if posColT < 0 || col <= posColT || posRowT < 0 || row <= posRowT {
						continue
					}
					id := posRowT*col + posColT
					mGridId[id] = id
				}
			}
		}
	}

	gridList := layer.GridList
	for key := range mGridId { // 锁住怪周围的砖块
		if val, ok := gridList[key]; ok {
			// 格子上有砖块或焦土 就要锁住
			// 1、格子无砖，无焦土，不锁格子 status=0,Tid>0,ExtId=0
			// 2、格子有砖，无焦土，锁格子   status=1,Tid>0 && Tid!=9999,ExtId=0
			// 3、格子无砖，有焦土，锁格子   status=1,Tid=9999,ExtId=0
			// 4、格子有砖，有焦土，锁格子   status=2,Tid=9999,ExtId>0
			if val.Status > 0 {
				val.StatusEx = 1
				r[key] = val
			}
		}
	}
	layer.Update(layer)
	return
}

// 解锁怪锁住的砖块 gid怪当前格子id
func MonsterUnlockBrick(u *m.User, gid int64) (r map[int64]*m.GridInfo, err error) {
	layer := u.GetLayer()
	layerT, ok := getLayerTByTid(uint64(layer.Tid))
	if !ok {
		err = errors.NewErrcode(data.Errcode.ConfigNotFound, "没有找到层配置")
		return
	}

	col := int64(layerT.Column) // 列
	row := int64(len(layer.GridList)) / col

	gridList := layer.GridList
	r = make(map[int64]*m.GridInfo)

	// 计算周围8个格子id
	posCol := gid % col
	posRow := gid / col
	for posColT := posCol - 1; posColT <= posCol+1; posColT++ {
		for posRowT := posRow - 1; posRowT <= posRow+1; posRowT++ {
			// 越界 不做计算
			if posColT < 0 || col <= posColT || posRowT < 0 || row <= posRowT {
				continue
			}
			id := posRowT*col + posColT
			// 该格子被锁住，解锁。
			if val, ok := gridList[id]; ok && val.StatusEx == 1 {
				unlock := true
				// 判断解锁格子周围有没有怪，如果有怪，不解锁，没有怪，解锁格子。
				for unPosCol := posColT - 1; unPosCol <= posColT+1; unPosCol++ {
					for unPosRow := posRowT - 1; unPosRow <= posRowT+1; unPosRow++ {
						// 越界不做判断
						if unPosCol < 0 || col <= unPosCol || unPosRow < 0 || row <= unPosRow {
							continue
						}
						unId := unPosRow*col + unPosCol
						valT, okT := gridList[unId]
						// 该格子存在，格子打开，格子上有怪
						if okT &&
							valT.Status == 0 &&
							valT.Goods != nil &&
							IsMonster(valT.Goods.Tid) {

							unlock = false
							break
						}
					}
				}
				if unlock {
					val.StatusEx = 0
					r[val.Id] = val
				}
			}
		}
	}
	layer.Update(layer)
	return
}
